package com.zdhy.zoc.collect.snmp;

import com.loong.collect.snmp4j.SnmpResult;
import com.zdhy.zoc.collect.snmp.model.ModelSnmp;
import org.apache.log4j.Logger;
import org.snmp4j.*;
import org.snmp4j.event.ResponseEvent;
import org.snmp4j.event.ResponseListener;
import org.snmp4j.mp.MPv3;
import org.snmp4j.mp.SnmpConstants;
import org.snmp4j.security.*;
import org.snmp4j.smi.*;
import org.snmp4j.transport.DefaultUdpTransportMapping;
import org.snmp4j.util.DefaultPDUFactory;
import org.snmp4j.util.TableEvent;
import org.snmp4j.util.TableUtils;

import java.io.IOException;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Vector;

/**
 * Created by 梁浩峰 on 2016/8/24 15:11.
 */
public class SnmpUtil {
    private static Logger log=Logger.getLogger(SnmpUtil.class);
    public final static int SNMP_V2 = 2;
    public final static int SNMP_V3 = 3;

    public static HashMap<OID, String> v2walk(CommunityTarget target, OID[] oids) throws Exception {
        Snmp snmp = new Snmp(new DefaultUdpTransportMapping());
        snmp.listen();

        TableUtils utils = new TableUtils(snmp, new DefaultPDUFactory(PDU.GETNEXT));
        utils.setMaxNumRowsPerPDU(5);
        List<TableEvent> events = utils.getTable(target, oids, null, null);
        HashMap<OID, String> map = new HashMap<OID, String>();
        for (TableEvent e : events
                ) {
            VariableBinding[] columns = e.getColumns();
            for (VariableBinding vb:columns
                 ) {
                if(vb!=null)
                System.out.println(vb.getOid().toString().substring(21,22)+"==>"+vb.toValueString());
            }
//            map.put(e.getIndex(), e.getColumns()[0].toValueString());
        }
        return map;
    }

    public static Address produceAddress(String hosts, String port) {
        UdpAddress address = new UdpAddress(hosts + "/" + port);
        return address;
    }

    public static HashMap<OID, String> v3walk(CommunityTarget target, String oid, OctetString contextEngineId) throws Exception {
        Snmp snmp = new Snmp(new DefaultUdpTransportMapping());
        USM usm = new USM(SecurityProtocols.getInstance(), new OctetString(MPv3.createLocalEngineID()), 0);
        SecurityModels.getInstance().addSecurityModel(usm);
        snmp.listen();

        UsmUser user = new UsmUser(
                new OctetString("nmsAdmin"),
                AuthMD5.ID, new OctetString("nmsAuthKey"),
                PrivDES.ID, new OctetString("nmsPrivKey"));
        snmp.getUSM().addUser(new OctetString("nmsAdmin"), user);

        TableUtils utils = new TableUtils(snmp, new MyDefaultPDUFactory(PDU.GETNEXT, contextEngineId));
        utils.setMaxNumRowsPerPDU(5);
        OID[] oids = {new OID(oid)};
        List<TableEvent> events = utils.getTable(target, oids, null, null);
        HashMap<OID, String> map = new HashMap<OID, String>();
        for (TableEvent e : events
                ) {
            map.put(e.getIndex(), e.getColumns()[0].toValueString());
        }
        return map;
    }


    public static CommunityTarget setting(ModelSnmp ms) {
        CommunityTarget target = new CommunityTarget();
        target.setAddress(produceAddress(ms.getHosts(),ms.getPort()));
        if(ms.getSnmpVersion()==2){
            target.setCommunity(ms.getReadName());
            target.setVersion(SnmpConstants.version2c);
        }else if(ms.getSnmpVersion() ==3){
            target.setVersion(SnmpConstants.version3);
            target.setSecurityLevel(SecurityLevel.AUTH_PRIV);
            target.setSecurityName(ms.getReadName());
        }else{

        }
        target.setTimeout(6000);
        target.setRetries(1);
        return target;

    }



    private static class MyDefaultPDUFactory extends DefaultPDUFactory {
        private OctetString contextEngineId = null;

        public MyDefaultPDUFactory(int pduType, OctetString contextEngineId) {
            super(pduType);
            this.contextEngineId = contextEngineId;
        }

        @Override
        public PDU createPDU(Target target) {
            PDU pdu = super.createPDU(target);
            if (target.getVersion() == SnmpConstants.version3) {
                ((ScopedPDU) pdu).setContextEngineID(contextEngineId);
            }
            return pdu;
        }
    }


    public static HashMap<OID, String> snmpWalk(ModelSnmp ms,OID[] oids) throws Exception {
        CommunityTarget setting = setting(ms);
        HashMap<OID, String> walk = v2walk(setting, oids);
        return walk;
    }

    public static Boolean snmpPing(CommunityTarget target) throws Exception {
        Boolean satus = false;
        try {
            Snmp snmp = new Snmp(new DefaultUdpTransportMapping()); //构造一个UDP
            snmp.listen();
            PDU pdu = new PDU();
            pdu.setType(PDU.GETBULK);
            pdu.setMaxRepetitions(1);
            pdu.setNonRepeaters(0);
            pdu.add(new VariableBinding(new OID("1.3")));
            ResponseEvent responseEvent = snmp.send(pdu, target);
            PDU response = responseEvent.getResponse();
            if (response == null) {
            } else {
                if (response.getErrorStatus() == PDU.noError) {
                    satus = true;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return satus;
    }

    public static Boolean isAddressAvailable(String ip){
        Boolean status=false;
        try{
            InetAddress address = InetAddress.getByName(ip);//ping this IP
            boolean reachable = address.isReachable(5000);
            if(reachable) {
                status = true;
            }
        }catch(Exception e){
            log.error("error occurs.");
            e.printStackTrace();
        }
        return status;
    }
}

